//
//  QSWebView.m
//  QSSmarkPark-iOS
//
//  Created by 孙俊 on 2018/3/14.
//  Copyright © 2018年 QiSheng. All rights reserved.
//

#import "QSWebView.h"
#import "QSSystemToolsHelper.h"

@interface QSWebView ()<WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate>

@property (nonatomic, assign) double estimatedProgress;
@property (nonatomic, strong) NSURLRequest* originRequest;
@property (nonatomic, strong) NSURLRequest* currentRequest;

@property (nonatomic, copy) NSString *title;

@property (strong, nonatomic) UIProgressView *progressView;

@end

@implementation QSWebView

- (instancetype)init
{
    return [self initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self initWKWebView];
    }
    return self;
}

- (void)initWKWebView
{
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    configuration.userContentController = [WKUserContentController new];
    
    WKPreferences *preferences = [WKPreferences new];
    preferences.javaScriptCanOpenWindowsAutomatically = YES;
    configuration.preferences = preferences;
    
    WKWebView *webView = [[WKWebView alloc] initWithFrame:self.bounds configuration:configuration];
    webView.UIDelegate = self;
    webView.navigationDelegate = self;
    webView.allowsBackForwardNavigationGestures = YES;
    webView.backgroundColor = [UIColor whiteColor];
    
    webView.backgroundColor = [UIColor clearColor];
    webView.opaque = NO;
    
    if (@available(iOS 11.0, *)) {
        webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    }
    
    webView.scrollView.delegate = self;
    webView.scrollView.bounces = NO;
    
    [webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    [webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
    _realWebView = webView;
    [self addSubview:self.realWebView];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.realWebView.frame = self.bounds;
}

- (void)setDelegate:(id<QSWebViewDelegate>)delegate
{
    _delegate = delegate;
    WKWebView *webView = self.realWebView;
    webView.UIDelegate = nil;
    webView.navigationDelegate = nil;
    webView.UIDelegate = self;
    webView.navigationDelegate = self;
}

- (void)addScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name
{
    WKWebViewConfiguration *configuration = [self.realWebView configuration];
    [configuration.userContentController addScriptMessageHandler:scriptMessageHandler name:name];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        self.estimatedProgress = [change[NSKeyValueChangeNewKey] doubleValue];
        [self.progressView setAlpha:1.0f];
        [self.progressView setProgress:self.estimatedProgress animated:YES];
        if(_realWebView.estimatedProgress >= 1.0f)
        {
            [UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
                [self.progressView setAlpha:0.0f];
            } completion:^(BOOL finished) {
                [self.progressView setProgress:0.0f animated:NO];
            }];
        }
    }
    else if ([keyPath isEqualToString:@"title"]) {
        self.title = change[NSKeyValueChangeNewKey];
        if (self.titleDidChangeBlock) {
            self.titleDidChangeBlock(change[NSKeyValueChangeNewKey]);
        }
    }
    else {
        [self willChangeValueForKey:keyPath];
        [self didChangeValueForKey:keyPath];
    }
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if ([self.delegate respondsToSelector:@selector(webViewDidScroll:)]) {
        [self.delegate webViewDidScroll:scrollView];
    }
}

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSURLRequest *request        = navigationAction.request;
    NSString     *scheme         = [request.URL scheme];
    // decode for all URL to avoid url contains some special character so that it wasn't load.
    NSString     *absoluteString = [navigationAction.request.URL.absoluteString stringByRemovingPercentEncoding];
//    NSLog(@"Current URL is %@",absoluteString);
    
    static NSString *endPayRedirectURL = nil;
    
    // Wechat Pay, Note : modify redirect_url to resolve we couldn't return our app from wechat client.
//
    
    // Judge is whether to jump to other app.
    if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"about"]) {
        decisionHandler(WKNavigationActionPolicyCancel);
        
        //处理 tel，sms的scheme
        BOOL isLoadingDisableScheme = [self isLoadingWKWebViewDisableScheme:navigationAction.request.URL];
        if (isLoadingDisableScheme) {
            return;
        }
        
        //处理其他的scheme
        if ([scheme isEqualToString:@"weixin"]) {
            // The var endPayRedirectURL was our saved origin url's redirect address. We need to load it when we return from wechat client.
            if (endPayRedirectURL) {
                [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:endPayRedirectURL] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10]];
                endPayRedirectURL = nil;
            }
        }
        
        BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:request.URL];
        if (!canOpen && [scheme isEqualToString:@"weixin"]) {
            [QSAppKeyWindow showAutoHideHudWithText:@"您还没有安装微信，请先安装微信"];
        }
        if (canOpen) {
            [[UIApplication sharedApplication] openURL:request.URL];
        }
        return;
    }
    
    decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation* )navigation
{
    [self callback_webViewDidStartLoad];
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{    
    [self callback_webViewDidFinishLoad];
}

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation*)navigation withError:(NSError*)error
{
    [self callback_webViewDidFailLoadWithError:error];
}

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    [self callback_webViewDidFailLoadWithError:error];
}

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    [self callback_webViewDidCommitNavigation:navigation];
}

#pragma mark - CALLBACK QSWebView Delegate
- (void)callback_webViewDidFinishLoad
{
    if ([self.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
        [self.delegate webViewDidFinishLoad:self];
    }
}

- (void)callback_webViewDidStartLoad
{
    if ([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
        [self.delegate webViewDidStartLoad:self];
    }
}

- (void)callback_webViewDidFailLoadWithError:(NSError*)error
{
    if ([error code] == NSURLErrorCancelled) {
        return;
    }
    
    if ([self.delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
        [self.delegate webView:self didFailLoadWithError:error];
    }
}

- (void)callback_webViewDidCommitNavigation:(WKNavigation *)navigation
{
    if ([self.delegate respondsToSelector:@selector(webView:didCommitNavigation:)]) {
        [self.delegate webView:self didCommitNavigation:navigation];
    }
}

#pragma mark - 基础方法
///判断当前加载的url是否是WKWebView不能打开的协议类型
- (BOOL)isLoadingWKWebViewDisableScheme:(NSURL*)url
{
    BOOL retValue = NO;
    //判断是否正在加载WKWebview不能识别的协议类型：phone numbers, email address, maps, etc.
    if ([url.scheme isEqualToString:@"tel"]) {
        if ([[UIApplication sharedApplication] canOpenURL:url]) {
            if (@available(iOS 10.0, *)) {
                [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
            } else {
                [[UIApplication sharedApplication] openURL:url];
            }
            retValue = YES;
        }
    } else if ([url.scheme isEqualToString:@"sms"]) {
        NSString *sms = url.absoluteString;
        NSRange range = [sms rangeOfString:@"sms:"];//匹配得到的下标
        NSString *phone = [sms substringWithRange:NSMakeRange(range.length, sms.length - range.length)];
        [[QSSystemToolsHelper sharedHelper] showMessageView:@[phone]
                                                      title:@"短信"
                                                       body:nil
                                         inParentController:[UIViewController currentViewController]];
        retValue = YES;
    }
    return retValue;
}

- (UIScrollView *)scrollView
{
    return [(id)self.realWebView scrollView];
}

- (id)loadRequest:(NSURLRequest*)request
{
    self.originRequest = request;
    self.currentRequest = request;
    
    return [self.realWebView loadRequest:request];
}

- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL
{
    return [self.realWebView loadHTMLString:string baseURL:baseURL];
}

- (NSURLRequest *)currentRequest
{
    return _currentRequest;
}

- (NSURL *)URL
{
    return [self.realWebView URL];
}

- (BOOL)isLoading
{
    return [self.realWebView isLoading];
}

- (BOOL)canGoBack
{
    return [self.realWebView canGoBack];
}

- (id)goBack
{
    return [self.realWebView goBack];
}

- (BOOL)canGoForward
{
    return [self.realWebView canGoForward];
}

- (id)goForward
{
    return [self.realWebView goForward];
}

- (id)reload
{
    return [self.realWebView reload];
}

- (id)reloadFromOrigin
{
    return [self.realWebView reloadFromOrigin];
}

- (void)stopLoading
{
    [self.realWebView stopLoading];
}

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler
{
    return [self.realWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
}

/** 清理缓存的方法，这个方法会清除缓存类型为HTML类型的文件*/
- (void)clearCache
{
    if (@available(iOS 9.0, *)) {

        NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
        
        /*
         <WKNSArray 0x170453e30>(
         <WKWebsiteDataRecord: 0x1702e8880; displayName = test176.cn; dataTypes = { Disk Cache, Cookies, Session Storage, Local Storage }>,
         <WKWebsiteDataRecord: 0x1702e7600; displayName = hzqisheng.cn; dataTypes = { Disk Cache }>,
         <WKWebsiteDataRecord: 0x1702e5c80; displayName = unpkg.com; dataTypes = { Disk Cache }>,
         <WKWebsiteDataRecord: 0x1702e7300; displayName = amap.com; dataTypes = { Disk Cache }>
         )
         
         NSArray * types =@[WKWebsiteDataTypeMemoryCache,WKWebsiteDataTypeDiskCache]; // 9.0之后才有的
         NSSet *websiteDataTypes = [NSSet setWithArray:types];
         [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) {
         
         }];
         */
        
        [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:dateFrom completionHandler:^{
        }];
        return;
    }
    
    /* 取得Library文件夹的位置*/
    NSString *libraryDir = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0];
    /* 取得bundle id，用作文件拼接用*/
    NSString *bundleId  =  [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];
    /*
     * 拼接缓存地址，具体目录为App/Library/Caches/你的APPBundleID/fsCachedData
     */
    NSString *webKitFolderInCachesfs = [NSString stringWithFormat:@"%@/Caches/%@/fsCachedData",libraryDir,bundleId];
    
    NSError *error;
    /* 取得目录下所有的文件，取得文件数组*/
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *fileList = [[NSArray alloc] init];
    //fileList便是包含有该文件夹下所有文件的文件名及文件夹名的数组
    fileList = [fileManager contentsOfDirectoryAtPath:webKitFolderInCachesfs error:&error];
    
//    DLog(@"webview缓存路径==%@,fileList%@",webKitFolderInCachesfs,fileList);
    /* 遍历文件组成的数组*/
    for(NSString * fileName in fileList){
        /* 定位每个文件的位置*/
        NSString * path = [[NSBundle bundleWithPath:webKitFolderInCachesfs] pathForResource:fileName ofType:@""];
        /* 将文件转换为NSData类型的数据*/
        NSData * fileData = [NSData dataWithContentsOfFile:path];
        /* 如果FileData的长度大于2，说明FileData不为空*/
        if(fileData.length > 2){
            /* 创建两个用于显示文件类型的变量*/
            int char1 = 0;
            int char2 = 0;
            
            [fileData getBytes:&char1 range:NSMakeRange(0, 1)];
            [fileData getBytes:&char2 range:NSMakeRange(1, 1)];
            /* 拼接两个变量*/
            NSString *numStr = [NSString stringWithFormat:@"%i%i",char1,char2];
            /* 如果该文件前四个字符是6033，说明是Html文件，删除掉本地的缓存*/
            if([numStr isEqualToString:@"6033"]){
                [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@",webKitFolderInCachesfs,fileName] error:&error];
                continue;
            }
        }
    }
}

#pragma mark - **************** setter getter
- (UIProgressView *)progressView
{
    if(!_progressView)
    {
        _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 0)];
        _progressView.tintColor = [UIColor QSColorBlue1A8DEE];
        _progressView.trackTintColor = [UIColor whiteColor];
        [self addSubview:self.progressView];
    }
    return _progressView;
}

- (void)setShowProgressView:(BOOL)showProgressView
{
    _showProgressView = showProgressView;
    self.progressView.hidden = !showProgressView;
}

- (void)setProgressViewColor:(UIColor *)progressViewColor {
    _progressViewColor = progressViewColor;
    _progressView.tintColor = progressViewColor;
}

- (void)dealloc
{
    WKWebView *webView = _realWebView;
    webView.UIDelegate = nil;
    webView.navigationDelegate = nil;
    
    [webView removeObserver:self forKeyPath:@"estimatedProgress"];
    [webView removeObserver:self forKeyPath:@"title"];
    [_realWebView scrollView].delegate = nil;
    [_realWebView stopLoading];
    [_realWebView loadHTMLString:@"" baseURL:nil];
    [_realWebView stopLoading];
    [_realWebView removeFromSuperview];
    _realWebView = nil;
    [self clearCache];
    DLog(@"%@ dealloc",[self class]);
}

@end
